﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using BreakOutBattles.Game.Events;
#endregion

namespace BreakOutBattles.Game
{
    #region Enums
    public enum ResetPlayerOptions
    {
        ALL,
        ALL_NOT_SCORE
    }
    #endregion

    /// <summary>
    /// Represents a player in the game. A player can either be local or network controlled.
    /// </summary>
    public class Player
    {
        #region Delegates and Events
        public delegate void OutOfLifesEventHandler(object sender, object args);
        public event OutOfLifesEventHandler OutOfLifes;
        #endregion

        #region Fields
        private const int LIFE_BONUS = 200;
        private const int SPEC_ITEM_BONUS = 300;

        private string name;
        private bool isRemotePlayer = false;
        private bool totalScoreCalculated  = false;
        private int specialItems = 0;
        private int totalScore = 0;
        private int playerIndex = 1;
        private int roundsWon = 0;
        private int score = 0;
        private int defaultLifes = 0;
        private int lifes = 0;
        #endregion

        public Player()
        { }

        /// <summary>
        /// Creates a new Player.
        /// </summary>
        /// <param name="playerIndex">A unique index that indetifies a player in the game</param>
        /// <param name="isRemotePlayer">Wether or not the player is remote.</param>
        /// <param name="name">The name of the player.</param>
        public Player(int playerIndex, bool isRemotePlayer, string name = "player", int lifes = 1)
        {
            this.name = name;
            this.playerIndex = playerIndex;
            this.isRemotePlayer = isRemotePlayer;
            this.lifes = lifes;
            defaultLifes = lifes;
        }

        /// <summary>
        /// Resets the player properties to its default values.
        /// </summary>
        public void Reset(ResetPlayerOptions resetOptions)
        {
            switch (resetOptions)
            {
                case ResetPlayerOptions.ALL:
                    score = 0;
                    lifes = defaultLifes;
                    break;

                case ResetPlayerOptions.ALL_NOT_SCORE:
                    lifes = defaultLifes;
                    totalScoreCalculated = false;
                    break;

                default:
                    break;
            }
        }

        /// <summary>
        /// Gets and sets the name of the player.
        /// </summary>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// Gets and sets the current player score.
        /// </summary>
        public int Score
        {
            get { return score; }
            set { score = value; }
        }

        /// <summary>
        /// Gets and sets the number of lifes left. Fires
        /// OutOfLifesEvent if the number of lifes left is bellow one.
        /// </summary>
        public int Lifes
        {
            get { return lifes; }
            set
            {
                lifes = value;

                if (lifes < 1)
                {
                    FireOutOfLifesEvent();
                }
            }
        }

        /// <summary>
        /// Gets and sets the number of rounds this player have won.
        /// </summary>
        public int RoundsWon
        {
            get { return roundsWon; }
            set { roundsWon = value; }
        }

        /// <summary>
        /// Gets and sets the player index.
        /// </summary>
        public int PlayerIndex
        {
            get { return playerIndex; }
            set { playerIndex = value; }
        }

        /// <summary>
        /// Gets and sets a value that indicates if the player is
        /// remote or not.
        /// </summary>
        public bool IsRemotePlayer
        {
            get { return isRemotePlayer; }
            set { isRemotePlayer = value; }
        }

        /// <summary>
        /// Fires an event indicating that the player is out of lifes.
        /// </summary>
        private void FireOutOfLifesEvent()
        {
            if (OutOfLifes != null)
            {
                OutOfLifes(this, null);
            }
        }

        /// <summary>
        /// A handler to the BrickDestroyed event. Affects the player score.
        /// </summary>
        public void BrickDestroyedHandler(object sender, BrickDestroyedArgs args)
        {
            Score += args.destructionBonus;
        }

        /// <summary>
        /// A handler to the BallOutofBounds event. Affects the number of lifes available.
        /// </summary>
        public void BallOutOfBoundsHandler(object sender, object args)
        {
            Lifes--;
        }

        /// <summary>
        /// Gets ans sets the number of special items this player collected on the last
        /// game round.
        /// </summary>
        public int SpecialItems
        {
            get
            {
                return specialItems;
            }
            set
            {
                specialItems = value;
            }
        }

        /// <summary>
        /// Gets the totalscore. The total score is calculated once per game round.
        /// </summary>
        public int TotalScore
        {
            get
            {
                if (!totalScoreCalculated)
                {
                    totalScore += score + (Lifes * LIFE_BONUS) + (SpecialItems * SPEC_ITEM_BONUS);
                    totalScoreCalculated = true;
                }

                return totalScore;
            }
        }
    }
}
